package com.hyperzsoft.utils;

import java.util.Arrays;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;

import com.hyperzsoft.budget.R;

//XML layout used to display this bar
//xmlns:hyperz="http://schemas.android.com/apk/res/com.hyperzsoft.budget"
//<view class="com.hyperzsoft.utils.ColorSelectBar"
//hyperz:barStrokeWidth="5"
//hyperz:barStrokeHeight="40"
//hyperz:defaultColor="-16711936"
//android:id="@+id/test_view"
//android:layout_width="fill_parent"
//android:layout_height="wrap_content"/>
//
//Code used to get the color of the bar
//ColorSelectBar csv = (ColorSelectBar) findViewById(R.id.test_view);
//csv.getColor();
//
//Code used to set the color of the bar to the closest color
//((ColorSelectBar) findViewById(R.id.colorBarViewID)).setColor(Color.rgb(255, 128, 0));

public class ColorSelectBar extends View {

	private static final int RED = 0;
	private static final int GREEN = 1;
	private static final int BLUE = 2;
	private static final int mHueBarXBuffer = 2;
	private static final int mHueBarYBuffer = 5;
	
	private final Paint mPaint;
	private final int[] mHueBarColors = new int[64];
	private final int mStrokeWidth;
	private final int mStrokeHeight;
	private final int[] rgb = {255, 0, 0};
	private final int mHueIncrement = 24;
	private final int mDefaultColor;
	
	private int mHueArrayIndex = 0;
	private int mSetColor;
	private final GestureDetector mGestureDetector;
	
	public ColorSelectBar(Context c, AttributeSet attrs) {
		super(c, attrs);
		
		//get any custom attributes set in the XML
		TypedArray customAttrs = getContext().obtainStyledAttributes(attrs, R.styleable.ColorSelectBar);
		mStrokeWidth = customAttrs.getInteger(R.styleable.ColorSelectBar_barStrokeWidth, 5);
		mStrokeHeight = customAttrs.getInteger(R.styleable.ColorSelectBar_barStrokeHeight, 40);
		mDefaultColor = customAttrs.getInteger(R.styleable.ColorSelectBar_defaultColor, Color.RED);
		
		// Initialize the colors of the hue slider bar
		buildColorsArray();
		setColor(mDefaultColor);
		
		// Initializes the Paint that will draw the View
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setTextAlign(Paint.Align.CENTER);
		mPaint.setTextSize(12);
		
		mGestureDetector = new GestureDetector(new customGestureListener());
	}
	
	private void buildColorsArray() {
		setupColorArray(GREEN, true);
		setupColorArray(RED);
		setupColorArray(BLUE, true);
		setupColorArray(GREEN);
		setupColorArray(RED, true);
		setupColorArray(BLUE);
	}
	
	/** Calls private void setupColorArray(int colorIndex, boolean isIncreasing)
	 *  with False so always Decreases.
	 * @param colorIndex
	 */
	private void setupColorArray(int colorIndex) {
		setupColorArray(colorIndex, false);
	}
	
	private void setupColorArray(int colorIndex, boolean isIncreasing) {
		if (isIncreasing) {
			rgb[colorIndex] = (colorIndex == 1) ? 0 : 23; 
			for (int i=rgb[colorIndex]; i<256; i += mHueIncrement) {
				rgb[colorIndex] = i;
				mHueBarColors[mHueArrayIndex] = Color.rgb(rgb[0], rgb[1], rgb[2]);
				mHueArrayIndex++;
			}
		} else {
			for (int i=243; i>=0; i -= mHueIncrement) {
				rgb[colorIndex] = i;
				mHueBarColors[mHueArrayIndex] = Color.rgb(rgb[0], rgb[1], rgb[2]);
				mHueArrayIndex++;
			}
		}
	}
	
	/*
	 * Calls setColor(int color) with the default color defined in the ColorSelectBar styleable
	 */
	public void setColor() {
		setColor(mDefaultColor);
	}
	
	public void setColor(int color) {
		int foundIndex;
		
		int[] sortedColors = null;
		sortedColors = mHueBarColors.clone();
		
		Arrays.sort(sortedColors);
		foundIndex = Arrays.binarySearch(sortedColors, color);
		
		//validate the found index to avoid ArrayIndexOutOfBoundsExceptions :)
		foundIndex = (foundIndex == -1 || foundIndex > sortedColors.length) ? 0 : foundIndex;
		
		mSetColor = sortedColors[Math.abs(foundIndex)];
		sortedColors = null;
		invalidate();
	}
	
	public int getColor() {
		return mSetColor; 
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		float lineX;
		
		// Display all the colors of the hue bar with lines
		for (int x=0; x<64; x++)
		{
			if (mHueBarColors[x] == mSetColor) {
				mPaint.setColor(Color.BLACK);
			} else {
				mPaint.setColor(mHueBarColors[x]);
			}
			
			lineX = (x * mStrokeWidth) + mHueBarXBuffer;
			
			mPaint.setStrokeWidth(mStrokeWidth);
			canvas.drawLine(lineX, mHueBarYBuffer, lineX, mStrokeHeight, mPaint);
		}
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(mStrokeWidth * mHueBarColors.length, mStrokeHeight + mHueBarYBuffer);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return mGestureDetector.onTouchEvent(event);
	}
	
	private class customGestureListener extends SimpleOnGestureListener {
		private float x;
	    private float y;
	    
		public boolean onDown(MotionEvent event) {
			int selectedIndex;
			
			x = event.getX();
			y = event.getY();
			
			//verify the touch event is located in the hue bar
			if (x > mHueBarXBuffer && 
					x < 64 * mStrokeWidth + (mHueBarXBuffer) && 
					y > mHueBarYBuffer && 
					y < mStrokeHeight + mHueBarYBuffer)
			{
				x -= mHueBarXBuffer;
				// update the main field colors
				selectedIndex = (int)(x / mStrokeWidth);
				mSetColor = mHueBarColors[selectedIndex];
				
				// force the redraw of the view
				invalidate();
			}
			
			return true;
		}
	    
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        	x = e1.getX();
			y = e1.getY();
			float newX;
			
        	try {
            	if (x > mHueBarXBuffer && 
            			x < 64 * mStrokeWidth + (mHueBarXBuffer) && 
            			y > mHueBarYBuffer && 
            			y < mStrokeHeight + mHueBarYBuffer)
    			{
            		newX = e2.getX();
            		newX -= mHueBarXBuffer;
    				
            		// update the main field colors
    				int selectedIndex = (int)(newX / mStrokeWidth);
            		
            		mSetColor = mHueBarColors[selectedIndex];
    				
    				// force the redraw of the view
    				invalidate();
    			}
            } catch (Exception e) {
                // nothing
            }
            return false;
        }
    }
}